using System;
using System.Collections.Generic;
using System.Text;
using Physics2DDotNet;

namespace ElteIk.RoboSoccer.Core.PhysicsEngine
{
	/// <summary>
	/// Velocity and rotation limiter PhysicsLogic class. 
    /// Simulates some friction.
	/// </summary>
	class KineticEnergyLimiter : PhysicsLogic
	{
		public enum LimitationTypes
		{
			Linear,
            Exponential
		}

		LimitationTypes limitationType;
        Physics2DDotNetAdapter adapter;

		private float factor;

        private float ballLimitationFactor;

        /// <summary>
        /// Ball could have different factors.
        /// </summary>
        public float BallLimitationFactor
        {
            get { return ballLimitationFactor; }
            set { ballLimitationFactor = value; }
        }

        private float rotationCorrectionFactor;

        /// <summary>
        /// We usually limit the rotation more than the movement.
        /// </summary>
        public float RotationCorrectionFactor
        {
            get { return rotationCorrectionFactor; }
            set { rotationCorrectionFactor = value; }
        }

		public KineticEnergyLimiter(LimitationTypes limitationType, float factor, float ballFactor, float rotationCorrection, Physics2DDotNetAdapter adapter)
			: base(new Lifespan())
		{
			this.limitationType = limitationType;
			this.factor = factor;
            this.ballLimitationFactor = ballFactor;
            this.rotationCorrectionFactor = rotationCorrection;
            this.adapter = adapter;
		}

        public KineticEnergyLimiter(LimitationTypes limitationType, float factor, Physics2DDotNetAdapter adapter)
            : this(limitationType, factor, factor, 1.0f, adapter)
        {
        }

		protected override void RunLogic(float dt)
		{
			foreach (Body body in Bodies)
			{
                float factor = this.factor;
                if (adapter.bodiesMap[body] is Ball)
                    factor = ballLimitationFactor;

				switch (limitationType)
				{
					case LimitationTypes.Linear:
                         //Slow down the object

                        factor *= dt * 0.02f;

                        if (body.State.Velocity.Linear.Magnitude > 0f)
                        {
                            body.State.Velocity.Linear.Magnitude -= Math.Min(0.1f * factor + factor * body.State.Velocity.Linear.Magnitude, body.State.Velocity.Linear.Magnitude);
                        }

                        body.State.Velocity.Angular *= (1 - Math.Min(0.1f, 10f * rotationCorrectionFactor * factor));
                        break;


				}
			}
		}
	}
}
